import merge from '../help/merge.js';
import {
  calculateEncodingAttributes,
  getTotalWidthOfEncodings,
  getMaximumHeightOfEncodings
} from './shared.js';

var svgns = 'http://www.w3.org/2000/svg';

class SVGRenderer {
  constructor(svg, encodings, options) {
    this.svg = svg;
    this.encodings = encodings;
    this.options = options;
    this.document = options.xmlDocument || document;
  }

  render() {
    var currentX = this.options.marginLeft;

    this.prepareSVG();
    for (let i = 0; i < this.encodings.length; i++) {
      var encoding = this.encodings[i];
      var encodingOptions = merge(this.options, encoding.options);

      var group = this.createGroup(
        currentX,
        encodingOptions.marginTop,
        this.svg
      );

      this.setGroupOptions(group, encodingOptions);

      this.drawSvgBarcode(group, encodingOptions, encoding);
      this.drawSVGText(group, encodingOptions, encoding);

      currentX += encoding.width;
    }
  }

  prepareSVG() {
    // Clear the SVG
    while (this.svg.firstChild) {
      this.svg.removeChild(this.svg.firstChild);
    }

    calculateEncodingAttributes(this.encodings, this.options);
    var totalWidth = getTotalWidthOfEncodings(this.encodings);
    var maxHeight = getMaximumHeightOfEncodings(this.encodings);

    var width = totalWidth + this.options.marginLeft + this.options.marginRight;
    this.setSvgAttributes(width, maxHeight);

    if (this.options.background) {
      this.drawRect(0, 0, width, maxHeight, this.svg).setAttribute(
        'style',
        'fill:' + this.options.background + ';'
      );
    }
  }

  drawSvgBarcode(parent, options, encoding) {
    var binary = encoding.data;

    // Creates the barcode out of the encoded binary
    var yFrom;
    if (options.textPosition == 'top') {
      yFrom = options.fontSize + options.textMargin;
    } else {
      yFrom = 0;
    }

    var barWidth = 0;
    var x = 0;
    for (var b = 0; b < binary.length; b++) {
      x = b * options.width + encoding.barcodePadding;

      if (binary[b] === '1') {
        barWidth++;
      } else if (barWidth > 0) {
        this.drawRect(
          x - options.width * barWidth,
          yFrom,
          options.width * barWidth,
          options.height,
          parent
        );
        barWidth = 0;
      }
    }

    // Last draw is needed since the barcode ends with 1
    if (barWidth > 0) {
      this.drawRect(
        x - options.width * (barWidth - 1),
        yFrom,
        options.width * barWidth,
        options.height,
        parent
      );
    }
  }

  drawSVGText(parent, options, encoding) {
    var textElem = this.document.createElementNS(svgns, 'text');

    // Draw the text if displayValue is set
    if (options.displayValue) {
      var x, y;

      textElem.setAttribute(
        'style',
        'font:' +
          options.fontOptions +
          ' ' +
          options.fontSize +
          'px ' +
          options.font
      );

      if (options.textPosition == 'top') {
        y = options.fontSize - options.textMargin;
      } else {
        y = options.height + options.textMargin + options.fontSize;
      }

      // Draw the text in the correct X depending on the textAlign option
      if (options.textAlign == 'left' || encoding.barcodePadding > 0) {
        x = 0;
        textElem.setAttribute('text-anchor', 'start');
      } else if (options.textAlign == 'right') {
        x = encoding.width - 1;
        textElem.setAttribute('text-anchor', 'end');
      }
      // In all other cases, center the text
      else {
        x = encoding.width / 2;
        textElem.setAttribute('text-anchor', 'middle');
      }

      textElem.setAttribute('x', x);
      textElem.setAttribute('y', y);

      textElem.appendChild(this.document.createTextNode(encoding.text));

      parent.appendChild(textElem);
    }
  }

  setSvgAttributes(width, height) {
    var svg = this.svg;
    svg.setAttribute('width', width + 'px');
    svg.setAttribute('height', height + 'px');
    svg.setAttribute('x', '0px');
    svg.setAttribute('y', '0px');
    svg.setAttribute('viewBox', '0 0 ' + width + ' ' + height);

    svg.setAttribute('xmlns', svgns);
    svg.setAttribute('version', '1.1');

    svg.setAttribute('style', 'transform: translate(0,0)');
  }

  createGroup(x, y, parent) {
    var group = this.document.createElementNS(svgns, 'g');
    group.setAttribute('transform', 'translate(' + x + ', ' + y + ')');

    parent.appendChild(group);

    return group;
  }

  setGroupOptions(group, options) {
    group.setAttribute('style', 'fill:' + options.lineColor + ';');
  }

  drawRect(x, y, width, height, parent) {
    var rect = this.document.createElementNS(svgns, 'rect');

    rect.setAttribute('x', x);
    rect.setAttribute('y', y);
    rect.setAttribute('width', width);
    rect.setAttribute('height', height);

    parent.appendChild(rect);

    return rect;
  }
}

export default SVGRenderer;
